﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Reflection;
using ExcelDna.Integration;
using ExcelDna.Integration.Rtd;
using ExcelDna.ComInterop;
using FinPlusCompView;
using FinPlusAssembler;
using FinPlusInterfaces;

namespace FinPlusRTDService
{
    [Guid("B8875277-7A1D-4AF0-B6FF-B0C84CD4A9BA"), ProgId("rtservice")]
    public class FinPlusRTDService : FinPlusControl, IRtdServer
    {
        public override string Config { get { return "ExcelRTDService"; } }
        private IRTDUpdateEvent _callback;
        private static IDictionary<int, FinPlusCompView.FinPlusConnectService> _services;
        private static Config _config;
        private static Env _env = Env.unknown;
        private volatile static Object _lock = new Object();
        private static bool _hasInitialised;

        //public
        [ExcelFunction(Description = "assembly info", Category = "FinPlus.Assembly")]
        public static object FinPlusRTDServiceAssembly(){ return Assembly.GetExecutingAssembly().Info();}

        [ExcelFunction(Description = "service", Category = "FinPlus.Service")]
        public static object FinPlusService(object ServiceName, object ServiceType, object Parms, object keyFormat, object transpose)
        {
            try
            {
                var res = XlCall.Excel(XlCall.xlfRtd, "rtservice", null, ServiceName, ServiceType, Parms, keyFormat, transpose);
                return res.ToString().ToArray2d();
            }
            catch (Exception e)
            {
                Level.Error.Log(e.Message, e);
                return e;
            }
        }

        public void AutoClose()
        {

        }

        public void AutoOpen()
        {
            ComServer.DllRegisterServer();
        }

        public object ConnectData(int topicId, ref Array strings, ref bool newValues)
        {
            try
            {
                if (strings.Length != 5) 
                    return "#five parameters are required";

                _services[topicId] = new FinPlusCompView.FinPlusConnectService(strings.GetValue(0).ToString(), strings.GetValue(1).ToString(), strings.GetValue(2).ToString(), strings.GetValue(3).ToString(), bool.Parse(strings.GetValue(4).ToString()));
                //log.Log(Logger.LoggingLevel.Debug, "FinPlusService ConnectData " + _services[topicId].Name);            

                _callback.UpdateNotify();

                return GetPods(topicId);
            }
            catch (Exception e)
            {
                return e.ToString();
            }
        }

        public void DisconnectData(int topicId)
        {
            try
            {
                if (!_services.ContainsKey(topicId))
                    return;
                _services[topicId].Dispose();
                _services.Remove(topicId);
            }
            catch(Exception e) 
            {
                Level.Error.Log(e.Message, e);
            }
        }

        public int Heartbeat()
        {
            return 1;
        }

        public Array RefreshData(ref int topicCount)
        {
            //object[,] data = new object[2, _querys.Count];

            try
            {
                //int index = 0;

                //foreach (int topicId in _querys.Keys)
                //{
                //    data[0, index] = topicId;
                //    data[1, index] = GetPods(topicId);
                //    ++index;
                //}

                //topicCount = _querys.Count;
            }
            catch(Exception e)
            {
                Level.Error.Log(e.Message, e);
            }

            return null;
        }

        public int ServerStart(IRTDUpdateEvent callback)
        {
            try
            {
                _callback = callback;
                _services = new Dictionary<int, FinPlusCompView.FinPlusConnectService>();
                Connect();
            }
            catch(Exception e)
            {
                Level.Error.Log(e.Message, e);
                return 0;
            }

            return 1;
        }

        public void ServerTerminate()
        {
            try
            {
                if (_services != null)
                {
                    foreach(var service in _services.Values)
                        service.Dispose();
                }
            }
            catch(Exception e) 
            {
                Level.Error.Log(e.Message, e);
            }

            //log.Log(Logger.LoggingLevel.Debug, "FinPlusQry ServerTerminate");
        }

        //private
        private static object GetPods(int topic)
        {
            try
            {
                if (!_services.ContainsKey(topic)) return "Waiting!";
                return "????"; //_services[topic].FPods.ToString(FieldType.Value);
            }
            catch (Exception e)
            {
                Level.Error.Log(e.Message, e);
                return e.ToString();
            }
        }

        private void Connect()
        {
            try
            {
                //load config and initialize logger
                if (_hasInitialised) return;

                lock (_lock)
                {
                    if (_hasInitialised) return;

                    _hasInitialised = true;

                    var path = Assembly.GetExecutingAssembly().ConfigPath();
                    _config = path.ConfigXml(out _env);
               }
            }
            catch(Exception e)
            {
                Level.Error.Log(e.Message, e);
            }
        }

        //events
        private void Callback(object s, EventArgs a)
        {
            try
            {
                _callback.UpdateNotify();
            }
            catch(Exception e)
            {
                Level.Error.Log(e.Message, e);
            }
        }
    }
}